﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Xml;

using System.Data.SqlClient;
using System.IO;
using CommandsGenerator.Properties;
using System.Threading;
namespace CommandsGenerator
{
    #region Delegates
    /// <summary>
    /// Delegado que permitira crear un proceso asincrono para la generacion de comandos de todos los modulos.
    /// </summary>
    /// <returns></returns>
    delegate string GenertateAllCommandsDelegate();

    /// <summary>
    /// Delegado que permitira crear un proceso asincrono para la generacion de comandos de un modulo especifico.
    /// </summary>
    /// <returns></returns>
    delegate string GenertateSpecificsCommandsDelegate();
    #endregion
    
    /// <summary>
    /// Vista del generador de comandos
    /// </summary>
    /// <change who="Edson Fernandez" when="20100415" what="Creación" />
    public partial class CommandsGeneratorView : Form
    {
        #region Fields

        private string pUrlFile = @"C:\PRODEM\Microfinanzas\dev\src\Windows.FixedTermDeposit\Module\FixedTermDepositCommands.xml";
        private string pUser = "MFNET";
        private string pPassword = "MFNET2";
        private XmlNodeList pListCommandMain;
        private string pCnn = "";
        private DataTable dtDataFileCommands;

        private string pScriptExecute;
        private string pDescriptionModule;

        #endregion
      
        #region Constructor

        public CommandsGeneratorView()
        {
            InitializeComponent();
        }

        #endregion      

        #region Methods

        /// <summary>
        /// Metodo que encuentra los comandos eliminados del archivo XML
        /// </summary>
        /// <param name="vIdModule">id del modulo</param>
        /// <returns></returns>
        private List<long> GetCommandDeleted(long vIdModule)
        {
            
            List<long> vListResult = new List<long>();
            string vCondicion = "";

            vCondicion += pListCommandMain[0].Attributes.GetNamedItem("IdCommand").Value;
            for (int vIndex = 1; vIndex < pListCommandMain.Count; vIndex++)
            {
                vCondicion += ", " + pListCommandMain[vIndex].Attributes.GetNamedItem("IdCommand").Value;
            }            
            try
            {
                string vQuery = "SELECT c.IdCommand FROM Security.Command c  WHERE c.IdCommand NOT IN (" + vCondicion + ") and IdSystemModule = " + vIdModule.ToString();
                DataSet dsGenerado = ExecuteQuery(vQuery);

                if (dsGenerado.Tables[0].Rows.Count > 0)
                {
                    foreach (DataRow vRow in dsGenerado.Tables[0].Rows)
                    {
                        vListResult.Add(Convert.ToInt64(vRow[0]));
                    }
                }

            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }

            return vListResult;
        }

        /// <summary>
        /// Metodo que permite obtener los comandos nuevos del archivo XML
        /// </summary>
        /// <param name="vIdModule">id del modulo del archivo xml</param>
        /// <returns></returns>
        private List<XmlElement> GetCommandNews(long vIdModule)
        {
            List<XmlElement> vListResult = new List<XmlElement>();

            /////Buscamos en la BD todos comandos que no estan en el archivo XML            
            try
            {
                string vQuery = "SELECT c.IdCommand FROM Security.Command c  WHERE  IdSystemModule = " + vIdModule.ToString();
                DataSet dsGenerado = ExecuteQuery(vQuery);

                if (dsGenerado.Tables[0].Rows.Count > 0)
                {
                    ///buscamos todos los comandos del archivo en la base de datos, los que nos son encontrados quiere decir que es un nuevo comando.
                    foreach (XmlElement nodo in pListCommandMain)
                    {
                        XmlAttributeCollection vAtributosNodoActual = nodo.Attributes;

                        bool vExist = false;
                        foreach (DataRow vRow in dsGenerado.Tables[0].Rows)
                        {
                            if (Convert.ToInt64(vRow[0]) == Convert.ToInt64(vAtributosNodoActual.GetNamedItem("IdCommand").Value))
                            {
                                vExist = true;
                                break;
                            }
                        }
                        if (!vExist)
                        {
                            vListResult.Add(nodo);
                        }
                    }
                }
                else
                {
                    ///Se insertan en la coleccion resultante a todos los comandos ya que se trata de un nuevo modulo
                    foreach (XmlElement nodo in pListCommandMain)
                    {
                        XmlAttributeCollection vAtributosNodoActual = nodo.Attributes;
                        vListResult.Add(nodo);
                    }
                }

            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            return vListResult;
        }

        /// <summary>
        /// Metodo que permite obtener los comandos que se actualizaran 
        /// </summary>
        /// <param name="vIdModule">id del modulo</param>
        /// <returns></returns>
        private List<XmlElement> GetCommandUpdate(long vIdModule)
        {
            List<XmlElement> vListResult = new List<XmlElement>();

            string vCondicion = "";

            vCondicion += pListCommandMain[0].Attributes.GetNamedItem("IdCommand").Value;
            for (int vIndex = 1; vIndex < pListCommandMain.Count; vIndex++)
            {
                vCondicion += ", " + pListCommandMain[vIndex].Attributes.GetNamedItem("IdCommand").Value;
            }

            /////Buscamos en la BD todos comandos que no estan en el archivo XML            
            try
            {                
                string vQuery = "SELECT c.IdCommand FROM Security.Command c  WHERE c.IdCommand IN (" + vCondicion + ") ";
                DataSet dsGenerado = ExecuteQuery(vQuery);               

                if (dsGenerado.Tables[0].Rows.Count > 0)
                {
                    ///Obtenemos los nodos encontrados en la consulta
                    foreach (DataRow vRow in dsGenerado.Tables[0].Rows)
                    {
                        foreach (XmlElement nodo in pListCommandMain)
                        {
                            XmlAttributeCollection vAtributosNodoActual = nodo.Attributes;

                            if (Convert.ToInt64(vRow[0]) == Convert.ToInt64(vAtributosNodoActual.GetNamedItem("IdCommand").Value))
                            {
                                vListResult .Add (nodo);
                                break;
                            }
                            
                        }
                    }
                 }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            return vListResult;
        }

        /// <summary>
        /// Metodo que genera el script de insercion de un comando
        /// </summary>
        /// <param name="vNode">Nodo que se procesara</param>
        /// <param name="vIdModule">Modulo para el cualse esta analizando</param>
        /// <param name="vParent">Id de comando que es padre del nodo</param>
        /// <param name="NumberElement">Numero de elemento esto es necesario para no crear llafves duplicas en la tabla roles</param>
        /// <returns>script de insercion de comando</returns>
        private string GetScriptInsertCommand(XmlElement vNode ,long vIdModule,long vParent, long NumberElement)
        {
            XmlAttributeCollection vAtributes = vNode.Attributes;
            string InsertValues = "";
            ///IdCommand
            if (vAtributes.GetNamedItem("IdCommand") != null)
                InsertValues += vAtributes.GetNamedItem("IdCommand").Value.ToString ();
            else
                InsertValues += "0";

            InsertValues += ",";

              ///modal 
            if (vAtributes.GetNamedItem("modal") != null)
                InsertValues += "'" + vAtributes.GetNamedItem("modal").Value.ToString() + "'";
            else
                InsertValues += "'false'";

            InsertValues += ",";

            ///multiple
            if (vAtributes.GetNamedItem("multiple") != null)
                InsertValues += "'" + vAtributes.GetNamedItem("multiple").Value.ToString() + "'";                
            else
                InsertValues += "'false'";

            InsertValues += ",";


            ///ShortCut 
            if (vAtributes.GetNamedItem("ShortCut") != null)
                InsertValues += "'" + vAtributes.GetNamedItem("ShortCut").Value.ToString() + "'";
            else
                InsertValues += "''";

            InsertValues += ",";

             ///icon 
            if (vAtributes.GetNamedItem("icon") != null)
                InsertValues += "'" + vAtributes.GetNamedItem("icon").Value.ToString() + "'";
            else
                InsertValues += "''";

            InsertValues += ",";

            ///visible
            if (vAtributes.GetNamedItem("visible") != null)
                InsertValues += "'" + vAtributes.GetNamedItem("visible").Value.ToString() + "'";
            else
            {
                if (vParent == 0)
                    InsertValues += "'true'";
                else
                    InsertValues += "'false'";

            }

            InsertValues += ",";

            ///mode
            if (vAtributes.GetNamedItem("mode") != null)
            {
                switch (vAtributes.GetNamedItem("mode").Value.ToString().ToUpper ())
                {
                    case "NONE":
                        InsertValues += "0";
                        break;
                    case "CREATE":
                        InsertValues += "1";
                        break;
                    case "SHOW":
                        InsertValues += "2";
                        break;
                    case "UPDATE":
                        InsertValues += "3";
                        break;
                    case "DELETE":
                        InsertValues += "4";
                        break;
                    case "PRINT":
                        InsertValues += "5";
                        break;
                    case "SEARCH":
                        InsertValues += "6";
                        break;            
                    default:
                        InsertValues += "0";
                        break;
                }                
            }
            else
                InsertValues += "0";

            InsertValues += ",";

            ///EnableLocalization
            ///este valor no es utilizado en los XML de comandos
            InsertValues += "'false',";

            ///type
            if (vAtributes.GetNamedItem("type") != null)
                InsertValues += "'" + vAtributes.GetNamedItem("type").Value.ToString() + "'";
            else
                InsertValues += "''";
           
            InsertValues += ",";

             ///Url
            ///este valor no es utilizado en los XML de comandos
            InsertValues += "'',";


             ///ResourceKey
            ///este valor no es utilizado en los XML de comandos
            InsertValues += "'',";

            ///key
            if (vAtributes.GetNamedItem("key") != null)
                InsertValues += "'" + vAtributes.GetNamedItem("key").Value.ToString () + "'";
            else
                InsertValues += "''";

            InsertValues += ",";
       
            ///description 
            if (vAtributes.GetNamedItem("description") != null)
                InsertValues += "'" + vAtributes.GetNamedItem("description").Value.ToString() + "'";
            else
                InsertValues += "''";

            InsertValues += ",";
           

            ///title
            if (vAtributes.GetNamedItem("title") != null)
                InsertValues += "'" + vAtributes.GetNamedItem("title").Value.ToString() + "'";
            else
                InsertValues += "''";

            InsertValues += ",";

            ///IdSystemModule            
            InsertValues += ""+ vIdModule.ToString () +",";
           
            ///source
            ///este valor no es utilizado en los XML de comandos
            InsertValues += "'',";

            ///Parent            
            InsertValues += ""+ vParent.ToString () +",";

             ///IsCounterOption
            if (vAtributes.GetNamedItem("IsCounterOption") != null)
                InsertValues += "'" + vAtributes.GetNamedItem("IsCounterOption").Value.ToString() + "'";
            else
                InsertValues += "'false'";

            InsertValues += ",";

            ///WorksOffline
            ///este valor no es utilizado en los XML de comandos
            InsertValues += "'false',";

            ///OfflineCommandKey
            ///este valor no es utilizado en los XML de comandos
            InsertValues += "'0',";

            ///OrderBy
            if (vAtributes.GetNamedItem("orderby") != null)
                InsertValues += vAtributes.GetNamedItem("orderby").Value.ToString ();
            else
                ///Para el caso que no se tenga el orden entonces se inserta el idcommand
                InsertValues += vAtributes.GetNamedItem("IdCommand").Value.ToString ();


            /////roles 
            //if (vAtributes.GetNamedItem("icon") != null)
            //    InsertValues += "'" + vAtributes.GetNamedItem("icon").Value.ToString() + "'";
            //else
            //    InsertValues += "''";
                 

            ///Armamos el query completo para insercion del comando
            string vQuery = "INSERT INTO Security.Command([IdCommand],[Modal],[Multiple],[ShortCut],[Icon],[Visible],[Mode],[EnableLocalization],[Type],[Url]," +
                            "[ResourceKey],[CommandKey],[Description],[Title],[IdSystemModule],[Source],[Parent],[IsCounterOption],[WorksOffline],"+
                            "[OfflineCommandKey],[OrderBy]) ";
            vQuery += "VALUES (" + InsertValues + ") ";

            StringBuilder sbScripts = new StringBuilder();
            sbScripts.Append(vQuery);
            sbScripts.AppendLine();

            
            ///Armamos el query para insertar un query en la tabla de roles, 
            ///por defecto se le adicionara privilegios a la nueva funcionalidad al usuario admin
            
            
            ///Primero obtenemos el id maximo de la tabla tCommandInRole
            
           //DataSet vTableNumberMax = ExecuteQuery ("SELECT max (tir.IdCommandInRole) FROM Security.CommandInRole tir");
           //long NumberMax = Convert.ToInt64 (vTableNumberMax.Tables[0].Rows[0].ItemArray[0] ) + NumberElement ;

           string vQueryRole = "INSERT INTO Security.CommandInRole(IdRole,IdCommand) " +
                               "VALUES (1 , " + vAtributes.GetNamedItem("IdCommand").Value.ToString() + ")";
           sbScripts.Append(vQueryRole);

           return sbScripts.ToString();

            
        }

        /// <summary>
        /// Metodo que genera el script de actualizacion de un comando
        /// </summary>
        /// <param name="vNode">Nodo que se procesara</param>
        /// <param name="vIdModule">Modulo para el cualse esta analizando</param>
        /// <param name="vParent">Id de comando que es padre del nodo</param>
        /// <returns>script de insercion de comando</returns>
        private string GetScriptUpdateCommand(XmlElement vNode,long vIdModule,long vParent)
        {
            XmlAttributeCollection vAtributes = vNode.Attributes;
            string InsertValues = "";
            ///IdCommand
            if (vAtributes.GetNamedItem("IdCommand") != null)
                InsertValues += "[IdCommand] = " + vAtributes.GetNamedItem("IdCommand").Value.ToString ();
            else
                InsertValues += "[IdCommand] = 0";

            InsertValues += ",";

              ///modal 
            if (vAtributes.GetNamedItem("modal") != null)
                InsertValues += "[Modal] = '" + vAtributes.GetNamedItem("modal").Value.ToString() + "'";
            else
                InsertValues += "[Modal] = 'false'";

            InsertValues += ",";

            ///multiple
            if (vAtributes.GetNamedItem("multiple") != null)
                InsertValues += "[Multiple] = '" + vAtributes.GetNamedItem("multiple").Value.ToString() + "'";                
            else
                InsertValues += "[Multiple] = 'false'";

            InsertValues += ",";


            ///ShortCut 
            if (vAtributes.GetNamedItem("ShortCut") != null)
                InsertValues += "[ShortCut] ='" + vAtributes.GetNamedItem("ShortCut").Value.ToString() + "'";
            else
                InsertValues += "[ShortCut] =''";

            InsertValues += ",";

             ///icon 
            if (vAtributes.GetNamedItem("icon") != null)
                InsertValues += "[Icon] ='" + vAtributes.GetNamedItem("icon").Value.ToString() + "'";
            else
                InsertValues += "[Icon] =''";

            InsertValues += ",";

            ///visible
            if (vAtributes.GetNamedItem("visible") != null)
                InsertValues += "[Visible] = '" + vAtributes.GetNamedItem("visible").Value.ToString() + "'";
            else
            {
                
                InsertValues += "[Visible] = 'true'";
            }

            InsertValues += ",";

            ///mode
            if (vAtributes.GetNamedItem("mode") != null)
            {
                switch (vAtributes.GetNamedItem("mode").Value.ToString().ToUpper ())
                {
                    case "NONE":
                        InsertValues += "[Mode] = 0";
                        break;
                    case "CREATE":
                        InsertValues += "[Mode] = 1";
                        break;
                    case "SHOW":
                        InsertValues += "[Mode] = 2";
                        break;
                    case "UPDATE":
                        InsertValues += "[Mode] = 3";
                        break;
                    case "DELETE":
                        InsertValues += "[Mode] = 4";
                        break;
                    case "PRINT":
                        InsertValues += "[Mode] = 5";
                        break;
                    case "SEARCH":
                        InsertValues += "[Mode] = 6";
                        break;            
                    default:
                        InsertValues += "[Mode] = 0";
                        break;
                }                
            }
            else
                InsertValues += "[Mode] = 0";

            InsertValues += ",";

            ///EnableLocalization
            ///este valor no es utilizado en los XML de comandos
            //InsertValues += "'false',";

            ///type
            if (vAtributes.GetNamedItem("type") != null)
                InsertValues += "[Type] = '" + vAtributes.GetNamedItem("type").Value.ToString() + "'";
            else
                InsertValues += "[Type] = ''";
           
            InsertValues += ",";

             ///Url
            ///este valor no es utilizado en los XML de comandos
            //InsertValues += "'',";


             ///ResourceKey
            ///este valor no es utilizado en los XML de comandos
            //InsertValues += "'',";

            ///key
            if (vAtributes.GetNamedItem("key") != null)
                InsertValues += "[CommandKey] = '" + vAtributes.GetNamedItem("key").Value.ToString () + "'";
            else
                InsertValues += "[CommandKey] = '' ";

            InsertValues += ",";
       
            ///description 
            if (vAtributes.GetNamedItem("description") != null)
                InsertValues += "[Description] ='" + vAtributes.GetNamedItem("description").Value.ToString() + "'";
            else
                InsertValues += "[Description] =''";

            InsertValues += ",";
           

            ///title
            if (vAtributes.GetNamedItem("title") != null)
                InsertValues += "[Title] ='" + vAtributes.GetNamedItem("title").Value.ToString() + "'";
            else
                InsertValues += "[Title] =''";

            InsertValues += ",";

            ///IdSystemModule            
            InsertValues += "[IdSystemModule] ="+ vIdModule.ToString () +",";
           
            ///source
            ///este valor no es utilizado en los XML de comandos
            //InsertValues += "'',";

            ///Parent            
            InsertValues += "[Parent] = "+ vParent.ToString () +",";

             ///IsCounterOption
            if (vAtributes.GetNamedItem("IsCounterOption") != null)
                InsertValues += "[IsCounterOption] ='" + vAtributes.GetNamedItem("IsCounterOption").Value.ToString() + "'";
            else
                InsertValues += "[IsCounterOption] ='false'";

            InsertValues += ",";

            ///WorksOffline
            ///este valor no es utilizado en los XML de comandos
            //InsertValues += "'false',";

            ///OfflineCommandKey
            ///este valor no es utilizado en los XML de comandos
            //InsertValues += "'0',";

            ///OrderBy
            if (vAtributes.GetNamedItem("orderby") != null)
                InsertValues += "[OrderBy] = "+vAtributes.GetNamedItem("orderby").Value.ToString ();
            else
                ///Para el caso que no se tenga el orden entonces se inserta el idcommand
                InsertValues += "[OrderBy] = " +vAtributes.GetNamedItem("IdCommand").Value.ToString ();


            /////roles 
            //if (vAtributes.GetNamedItem("icon") != null)
            //    InsertValues += "'" + vAtributes.GetNamedItem("icon").Value.ToString() + "'";
            //else
            //    InsertValues += "''";
                 

            ///Armamos el query completo
            string vQuery = "UPDATE Security.Command SET";
            vQuery +=InsertValues ;
            vQuery += " WHERE IdCommand = " + vAtributes.GetNamedItem("IdCommand").Value.ToString();

            return vQuery;
        }

        /// <summary>
        /// metodo que genera el script de eliminacion de una comando
        /// </summary>
        /// <param name="vNode">Nodo que se procesara</param>
        /// <returns></returns>
        private string GetQueryDeleteCommand(long vIdCommand)
        {
            
            string vQuery = " DELETE FROM Security.CommandInRole WHERE IdCommand = " + vIdCommand.ToString() + 
                            " DELETE FROM Security.Command WHERE IdCommand = " + vIdCommand.ToString();
            return vQuery;
        }

        /// <summary>
        /// Metodo que verifica si existen duplicados en la BD mediante los IDs comandos introducidos en el archivo.
        /// </summary>
      /// <param name="vIdModule">Id de modulo</param>
      /// <returns></returns>
        private bool VerifyDupplicates(long vIdModule)
        {
            bool vResult = true;
            string vSubQuery = "";

            ///Armamos el cuerpo del subquery de la consulta sql
            vSubQuery += " SELECT   c.IdCommand  FROM  Security.Command c  WHERE   c.IdSystemModule=" + vIdModule .ToString () + "  AND c.IdCommand = " + pListCommandMain[0].Attributes.GetNamedItem("IdCommand").Value;

            for (int vIndex = 1; vIndex < pListCommandMain.Count; vIndex++)
            {

                vSubQuery += " UNION ALL " +
                             " SELECT   c.IdCommand  FROM  Security.Command c  WHERE  c.IdSystemModule=" + vIdModule.ToString() + " AND c.IdCommand = " + pListCommandMain[vIndex].Attributes.GetNamedItem("IdCommand").Value;

            }


            string vCondition = "";

            vCondition += pListCommandMain[0].Attributes.GetNamedItem("IdCommand").Value;
            for (int vIndex = 1; vIndex < pListCommandMain.Count; vIndex++)
            {
                vCondition += ", " + pListCommandMain[vIndex].Attributes.GetNamedItem("IdCommand").Value;
            }

            ///buscamos los comandos con los que se estan duplicando los ids de comandos del archivo XML
            string vQuery = " SELECT t.* " +
                            " FROM ( " +
                                     " SELECT COUNT( IdCommand) AS num ,IdCommand " +
                                     " FROM ( " +
                                                vSubQuery +
                                         "  ) a  " +
                                     " GROUP BY a.IdCommand " +
                             "     ) b INNER JOIN Security.Command t ON t.IdCommand = b.IdCommand " +
                             "  WHERE b.num >= 2";



            vQuery += " UNION ALL " +
            " SELECT *  FROM Security.Command t   WHERE t. IdCommand IN (" + vCondition + ")  AND t.IdSystemModule <> " + vIdModule.ToString ();

           
            try
            {
                DataSet dsGenerado = ExecuteQuery(vQuery);               

                if (dsGenerado.Tables[0].Rows.Count > 0)
                {
                    vResult = false;
                  
                    StringBuilder sbError = new StringBuilder();
                    
                    foreach (DataRow  vRow in dsGenerado.Tables [0].Rows )
                    {
                        sbError.Append("IdCommand : " + vRow["IdCommand"].ToString() + "     CommandKey : " + vRow["CommandKey"].ToString() + "     IdModule : " + vRow["IdSystemModule"].ToString() + "     Title : " + vRow["Title"].ToString());
                        sbError.AppendLine();
                    }
                    txtLogError.Text = sbError.ToString();
                  
                  
                }                
                
            }
            catch (Exception ex)
            {

                MessageBox.Show(ex.Message, "", MessageBoxButtons.OK, MessageBoxIcon.Error);
                this.EnableControlsProcess(true);
            }
            return vResult;
        }


        /// <summary>
        /// Metodo que verifica si existen duplicados en la BD mediante los keys comandos introducidos en el archivo.
        /// </summary>
        /// <param name="vIdModule">Id de modulo</param>
        /// <returns></returns>
        private bool VerifyDupplicatesCommandsKey(long vIdModule)
        {
            bool vResult = true;
            string vSubQuery = "";

            ///Armamos el cuerpo del subquery de la consulta sql
            vSubQuery += " SELECT   c.IdCommand  FROM  Security.Command c  WHERE   c.IdSystemModule=" + vIdModule.ToString() + "  AND c.CommandKey ='" + pListCommandMain[0].Attributes.GetNamedItem("key").Value+"'";

            for (int vIndex = 1; vIndex < pListCommandMain.Count; vIndex++)
            {

                vSubQuery += " UNION ALL " +
                             " SELECT   c.IdCommand  FROM  Security.Command c  WHERE  c.IdSystemModule=" + vIdModule.ToString() + " AND c.CommandKey = '" + pListCommandMain[vIndex].Attributes.GetNamedItem("key").Value + "'";

            }


            string vCondition = "";

            vCondition += "'" + pListCommandMain[0].Attributes.GetNamedItem("key").Value + "'";
            for (int vIndex = 1; vIndex < pListCommandMain.Count; vIndex++)
            {
                vCondition += ", '" + pListCommandMain[vIndex].Attributes.GetNamedItem("key").Value + "'";
            }

            ///buscamos los comandos con los que se estan duplicando los ids de comandos del archivo XML
            string vQuery = " SELECT t.* " +
                            " FROM ( " +
                                     " SELECT COUNT( IdCommand) AS num ,IdCommand " +
                                     " FROM ( " +
                                                vSubQuery +
                                         "  ) a  " +
                                     " GROUP BY a.IdCommand " +
                             "     ) b INNER JOIN Security.Command t ON t.IdCommand = b.IdCommand " +
                             "  WHERE b.num >= 2";



            vQuery += " UNION ALL " +
            " SELECT *  FROM Security.Command t   WHERE t. CommandKey IN (" + vCondition + ")  AND t.IdSystemModule <> " + vIdModule.ToString();


            try
            {
                DataSet dsGenerado = ExecuteQuery(vQuery);

                if (dsGenerado.Tables[0].Rows.Count > 0)
                {
                    vResult = false;

                    StringBuilder sbError = new StringBuilder();

                    foreach (DataRow vRow in dsGenerado.Tables[0].Rows)
                    {
                        sbError.Append("IdCommand : " + vRow["IdCommand"].ToString() + "     CommandKey : " + vRow["CommandKey"].ToString() + "     IdModule : " + vRow["IdSystemModule"].ToString() + "     Title : " + vRow["Title"].ToString());
                        sbError.AppendLine();
                    }
                    txtLogError.Text = sbError.ToString();


                }

            }
            catch (Exception ex)
            {

                MessageBox.Show(ex.Message, "", MessageBoxButtons.OK, MessageBoxIcon.Error);
                this.EnableControlsProcess(true);
            }
            return vResult;
        }
       
        /// <summary>
        /// Metodo que permite ejecutar el script generado
        /// </summary>
        /// <param name="vScripts">CAdena que contiene todo el srcipt a ejecutar</param>
        public void ExecuteTransaction(string vScripts)
        {
            if (vScripts != string.Empty)
            {
                // Creamos la conexión
                using (SqlConnection vConnection = new SqlConnection(this.pCnn))
                {
                    // Abrimos la conexión
                    vConnection.Open();
                    // Abrimos una transación en la conexión abierta
                    SqlTransaction vTransaction = vConnection.BeginTransaction();
                    // Creamos el objeto SqlCommand y asignamos los datos
                    // a los parámetros
                    SqlCommand vCommand = new SqlCommand();
                    vCommand.Connection = vConnection;
                    vCommand.CommandType = CommandType.Text;
                    vCommand.CommandText = vScripts;
                    // Asignamos la transacción al comando
                    vCommand.Transaction = vTransaction;
                    try
                    {
                        // Ejecutamos el comando
                        vCommand.ExecuteNonQuery();
                        // Si todo ha ido bien hacemos un "Commit" de la transacción
                        vTransaction.Commit();
                        MessageBox.Show("Comandos generados satisfactoriamente !!!", "Informacion", MessageBoxButtons.OK, MessageBoxIcon.Information);
                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show("ERROR : " + ex.Message, "ERROR!!!", MessageBoxButtons.OK, MessageBoxIcon.Error);
                        // Si se produce un error, desahacemos la transaccion (Rollback)
                        vTransaction.Rollback();

                    }
                    // No se hace falta cerrar la conexión porque está dentro de un "using"
                    vConnection.Close();
                }
            }
            else
                MessageBox.Show("No se tiene ningun comando por actualizar. ", "Informacion", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
        }

        /// <summary>
        /// Metodo que ejecuta consultas sql server
        /// </summary>
        /// <param name="vQuery">Query que se ejecutara</param>
        /// <returns></returns>
        private DataSet ExecuteQuery(string vQuery)
        {
            DataSet dsGenerado = new DataSet();

            ///Buscamos en la BD todos comandos que no estan en el archivo XML
            using (SqlConnection vCnn = new SqlConnection(this.pCnn))
            {
                try
                {
                    string vQueryToExecute = vQuery;

                    SqlDataAdapter daQuery = new SqlDataAdapter(vQueryToExecute, vCnn);

                    daQuery.Fill(dsGenerado, "Result");

                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message, "", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
            }

            
            return dsGenerado;
        }

        /// <summary>
        /// Metodo que permite obtener la ubicacion de los archivos 
        /// </summary>
        /// <param name="strString">Nombre de la carpeta </param>
        /// <returns></returns>
        private string GetPath(string strString)
        {
            string strPath = "";
            strPath = AppDomain.CurrentDomain.BaseDirectory.ToString();
            if (strPath.IndexOf(strString) != -1)
            {

                //Remove folder "/bin"
                strPath = strPath.Remove(strPath.IndexOf(strString), strPath.Length - strPath.IndexOf(strString));
                strPath += @"\" + strString;
            }
            else
                strPath += strString;

            return strPath;
        }

        /// <summary>
        /// Metodo que imprime un text en el log
        /// </summary>
        /// <param name="Text">texto que se desea mostra en el log</param>
        /// <param name="Spaces">numero de espacios entre lineas</param>
        private void PrintTextInLog(string Text, int Spaces)
        {
            StringBuilder sbScripts = new StringBuilder();
            sbScripts.Append(Text);

            for (int vNumber = 0; vNumber < Spaces; vNumber++)
            {
                sbScripts.AppendLine();
            }

            txtLog.Text += sbScripts.ToString();
        }

        /// <summary>
        /// Metodo que genera los comandos 
        /// </summary>
        private string  GenerateCommands()
        {
            string vResult = "";
            try
            {

                txtLog.Text = "";
                XmlDocument xDoc = new XmlDocument();
                StringBuilder sbScripts = new StringBuilder();
                ///cargamos los      del  archivo XML  que contenga como atributo ´command´
                xDoc.Load(pUrlFile);
                pListCommandMain = xDoc.GetElementsByTagName("command");
                long vIdModule = Convert.ToInt64(pListCommandMain[0].Attributes.GetNamedItem("IdCommand").Value);
                

                if (VerifyDupplicates(vIdModule))
                {
                    if (VerifyDupplicatesCommandsKey(vIdModule))
                    {
                        sbScripts.Append("--  MODULO : " + pDescriptionModule.ToUpper());
                        sbScripts.AppendLine();
                        sbScripts.AppendLine();

                        string vScript = "";

                        long vIdCommandParent = 0;

                        #region Delete Commands
                        ///Obtenemos los nodos con los comandos que se eliminaran
                        List<long> ColCommandDelete = GetCommandDeleted(vIdModule);
                        foreach (long vItem in ColCommandDelete)
                        {
                            vScript = GetQueryDeleteCommand(vItem);
                            sbScripts.Append(vScript);
                            sbScripts.AppendLine();
                        }

                        #endregion

                        #region Update commands
                        ///Obtenemos los nodos con los comandos que se Actualizaran                
                        List<XmlElement> ColElementUpdate = GetCommandUpdate(vIdModule);
                        ///Iteramos el resultado y generamos los scripts de actualizacion 
                        foreach (XmlElement vItem in ColElementUpdate)
                        {
                            if (vItem.ParentNode.Attributes.GetNamedItem("IdCommand") != null)
                                vIdCommandParent = Convert.ToInt64(vItem.ParentNode.Attributes.GetNamedItem("IdCommand").Value);
                            else
                                vIdCommandParent = 0;
                            vScript = GetScriptUpdateCommand(vItem,
                                                             vIdModule,
                                                             vIdCommandParent);
                            sbScripts.Append(vScript);
                            sbScripts.AppendLine();
                            sbScripts.AppendLine();
                        }
                        #endregion

                        #region Insert Commands
                     
                        ///Obtenemos los nodos con los comandos que se insertaran
                        ///Obtenemos el nuemero maximo del untimo registro de los roles
                        DataSet vTableNumberMax = ExecuteQuery("SELECT max (tir.IdCommandInRole) FROM Security.CommandInRole tir");
                        long NumberElement = Convert.ToInt64(vTableNumberMax.Tables[0].Rows[0].ItemArray[0]);

                        List<XmlElement> ColElementInsert = GetCommandNews(vIdModule);
                        
                        foreach (XmlElement vItem in ColElementInsert)
                        {
                            NumberElement++;
                            if (vItem.ParentNode.Attributes.GetNamedItem("IdCommand") != null)
                                vIdCommandParent = Convert.ToInt64(vItem.ParentNode.Attributes.GetNamedItem("IdCommand").Value);
                            else
                                vIdCommandParent = 0;
                            vScript = GetScriptInsertCommand(vItem,
                                                            vIdModule,
                                                            vIdCommandParent,
                                                            NumberElement);
                            sbScripts.Append(vScript);
                            sbScripts.AppendLine();
                            sbScripts.AppendLine();
                           
                        }
                        #endregion

                     

                        vResult = sbScripts.ToString();
                        txtLog.Text = sbScripts.ToString();

                        ExecuteTransaction(sbScripts.ToString());

                        PrintTextInLog("--Instrucciones ejecutadas satisfactoriamente!!!", 2);
                        EnableControlsProcess(true);
                    }
                    else
                    {
                        MessageBox.Show("En los comandos del archivo existen keys de comandos duplicados. Revise el listado de comandos con los cuales estan duplicados.", "", MessageBoxButtons.OK, MessageBoxIcon.Information);
                        this.EnableControlsProcess(true);
                    }

                }
                else
                {
                    MessageBox.Show("En los comandos del archivo existen Ids de comandos duplicados. Revise el listado de comandos con los cuales estan duplicados.", "", MessageBoxButtons.OK, MessageBoxIcon.Information);
                    this.EnableControlsProcess(true);
                }
            }
            catch (Exception ex)
            {
                EnableControlsProcess(true);
                MessageBox.Show("ERROR :"+ ex.Message , "Error!!!", MessageBoxButtons.OK, MessageBoxIcon.Error );
            }
            return vResult;
        }

        /// <summary>
        /// Metodo que genera los comandos de todos los modulos
        /// </summary>
        public string GenerateCommandsAllModules()
        {
            try
            {

                StringBuilder sbScripts = new StringBuilder();
                txtLog.Text = "";
                bool vExistError = false;
                string vDescriptionModule="";
                ///Obtenemos el nuemero maximo del untimo registro de los roles
                DataSet vTableNumberMax = ExecuteQuery("SELECT max (tir.IdCommandInRole) FROM Security.CommandInRole tir");
                long NumberElement = Convert.ToInt64(vTableNumberMax.Tables[0].Rows[0].ItemArray[0]);

                ///Buscamos los datos correspondientes al modulo
                foreach (DataRow vRow in dtDataFileCommands.Rows)
                {
                    //PrintTextInLog(vRow["ModuleName"].ToString().ToUpper(), 2);


                    pUrlFile = GetPath("src");
                    pUrlFile += @"\" + vRow["PathFolder"] + @"\" + vRow["NameFile"];

                    vDescriptionModule = vRow["ModuleName"].ToString().ToUpper();
                    XmlDocument xDoc = new XmlDocument();                    
                    ///cargamos los      del  archivo XML  que contenga como atributo ´command´
                    xDoc.Load(pUrlFile);
                    pListCommandMain = xDoc.GetElementsByTagName("command");
                    long vIdModule = Convert.ToInt64(pListCommandMain[0].Attributes.GetNamedItem("IdCommand").Value);
                

                    if (VerifyDupplicates(vIdModule))
                    {
                        if (VerifyDupplicatesCommandsKey(vIdModule))
                        {

                            string vScript = "";

                            long vIdCommandParent = 0;

                            sbScripts.Append("--  MODULO : " + vRow["ModuleName"].ToString().ToUpper());
                            sbScripts.AppendLine();
                            sbScripts.AppendLine();

                            #region Delete Commands
                            ///Obtenemos los nodos con los comandos que se eliminaran
                            List<long> ColCommandDelete = GetCommandDeleted(vIdModule);
                            foreach (long vItem in ColCommandDelete)
                            {
                                vScript = GetQueryDeleteCommand(vItem);
                                sbScripts.Append(vScript);
                                sbScripts.AppendLine();
                            }

                            #endregion

                            #region Update commands
                            ///Obtenemos los nodos con los comandos que se Actualizaran                
                            List<XmlElement> ColElementUpdate = GetCommandUpdate(vIdModule);
                            ///Iteramos el resultado y generamos los scripts de actualizacion 
                            foreach (XmlElement vItem in ColElementUpdate)
                            {
                                if (vItem.ParentNode.Attributes.GetNamedItem("IdCommand") != null)
                                    vIdCommandParent = Convert.ToInt64(vItem.ParentNode.Attributes.GetNamedItem("IdCommand").Value);
                                else
                                    vIdCommandParent = 0;
                                vScript = GetScriptUpdateCommand(vItem,
                                                                 vIdModule,
                                                                 vIdCommandParent);
                                sbScripts.Append(vScript);
                                sbScripts.AppendLine();
                                sbScripts.AppendLine();
                            }
                            #endregion

                            #region Insert Commands
                            ///Obtenemos los nodos con los comandos que se insertaran
                            List<XmlElement> ColElementInsert = GetCommandNews(vIdModule);
                            
                            foreach (XmlElement vItem in ColElementInsert)
                            {
                                NumberElement++;
                                if (vItem.ParentNode.Attributes.GetNamedItem("IdCommand") != null)
                                    vIdCommandParent = Convert.ToInt64(vItem.ParentNode.Attributes.GetNamedItem("IdCommand").Value);
                                else
                                    vIdCommandParent = 0;
                                vScript = GetScriptInsertCommand(vItem,
                                                                vIdModule,
                                                                vIdCommandParent,
                                                                NumberElement);
                                sbScripts.Append(vScript);
                                sbScripts.AppendLine();
                                sbScripts.AppendLine();
                               
                            }
                            #endregion

                          


                            this.txtLog.Text += sbScripts.ToString();


                        }
                        else
                        {
                            vExistError = true;
                
                            sbScripts.Append("Error en los comandos de : " + vDescriptionModule.ToUpper());
                            sbScripts.AppendLine();
                            sbScripts.AppendLine();
                            break;
                        }
                    }
                    else
                    {
                        vExistError = true;
                
                        sbScripts.Append("Error en los comandos de : " + vDescriptionModule.ToUpper());
                        sbScripts.AppendLine();
                        sbScripts.AppendLine();
                        break;
                    }
                }
                if (!vExistError)
                {
                    ExecuteTransaction(sbScripts.ToString());
                    txtLog.Text = sbScripts.ToString();
                    PrintTextInLog("--Instrucciones ejecutadas satisfactoriamente!!!", 2);
                    this.EnableControlsProcess(true);
                    return sbScripts.ToString();

                }

                else
                {
                    PrintTextInLog("Error en el archivo de comanods del modulo de " + vDescriptionModule, 2);
                    MessageBox.Show("En los comandos del archivo existen Ids de comandos duplicados. Revise el listado de comandos con los cuales estan duplicados.", "", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    this.EnableControlsProcess(true);
                }
            }
            catch (Exception ex)
            {
                
                MessageBox.Show("ERROR :" + ex.Message, "Error!!!", MessageBoxButtons.OK, MessageBoxIcon.Error);

                this.EnableControlsProcess(true);
            }

            return "Sin generar!";
           
        }

        /// <summary>
        /// Metodo que carga los datos de los archivos de comandos que estan contenidos en archivo de configuracion FilesNameCommands.xml
        /// </summary>
        private void LoadFilesCommands()
        {
            XmlDocument xDoc1 = new XmlDocument();
            StringBuilder sbScripts = new StringBuilder();
            string vPathFile = GetPath(@"CommandsGenerator");
            vPathFile += @"\FilesNameCommands.xml";
            ///crearmos una estructura que contendra los datos del archivo FilesNameCommands.xml
            xDoc1.Load(vPathFile);

            dtDataFileCommands = new DataTable("DataFileCommands");
            dtDataFileCommands.Columns.Add("NameFile", typeof(string));
            dtDataFileCommands.Columns.Add("ModuleName", typeof(string));
            dtDataFileCommands.Columns.Add("IdModule", typeof(string));
            dtDataFileCommands.Columns.Add("PathFolder", typeof(string));

            ///iteramos los nodos del XML y los insertamos en la estructura que se esta creando
            XmlNodeList pListNode = xDoc1.GetElementsByTagName("CommandModule");

            foreach (XmlElement nodo in pListNode)
            {
                DataRow vRow = dtDataFileCommands.NewRow();
                vRow["NameFile"] = nodo.Attributes.GetNamedItem("NameFile").Value;
                vRow["ModuleName"] = nodo.Attributes.GetNamedItem("ModuleName").Value;
                vRow["IdModule"] = nodo.Attributes.GetNamedItem("IdModule").Value;
                vRow["PathFolder"] = nodo.Attributes.GetNamedItem("PathFolder").Value;
                dtDataFileCommands.Rows.Add(vRow);
            }
            
            //listModules.DataSource = dtDataFileCommands;
            //listModules.DisplayMember = "ModuleName";
            //listModules.ValueMember = "IdModule";
        }

        /// <summary>
        /// Valida los datos de la vista
        /// </summary>
        /// <returns></returns>
        private bool ValidateData()
        {
            bool vResult = true;
            if (txtServidor.Text == string.Empty)
            {
                MessageBox.Show("Debe introducir un nombre de servidor.", "", MessageBoxButtons.OK, MessageBoxIcon.Error);
                errorProvider1.SetError(txtServidor, "Debe introducir un nombre de Base de datos.");
                return false;
            }
            if (txtBD.Text == string.Empty)
            {
                MessageBox.Show("Debe introducir un nombre de Base de datos.", "", MessageBoxButtons.OK, MessageBoxIcon.Error);                
                errorProvider1.SetError(txtBD, "Debe introducir un nombre de Base de datos.");
                return false;
            }
            

            errorProvider1.SetError(txtBD, "");
            errorProvider1.SetError(txtServidor, "");

            if (this.txtUser.Text == string.Empty)
            {
                MessageBox.Show("Debe introducir un USUARIO.", "", MessageBoxButtons.OK, MessageBoxIcon.Error);
                
                return false;
            }
            if (this.txtPassword.Text == string.Empty)
            {
                MessageBox.Show("Debe introducir un PASSWORD.", "", MessageBoxButtons.OK, MessageBoxIcon.Error);

                return false;
            }


            ///Validamos la conexion con la BD                         
            using (SqlConnection vConnection = new SqlConnection(this.pCnn))
            {
                try
                {                    
                    vConnection.Open();
                    vConnection.Close();
                }
                catch (Exception)
                {

                    MessageBox.Show("El nombre de servidor o bases datos no pueden ser encontradas. Verifique los datos e intentelo nuevamente.", "ERROR!!!", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    return false;
                }
               
            }
            return vResult;

        }

        /// <summary>
        /// Metodoq que activa y visualiza ciertos controles para el progreso del proceso de generacion de comandos
        /// </summary>
        /// <param name="Value"></param>
        public void EnableControlsProcess(bool Value)
        {
            txtBD.Enabled = Value;
            txtServidor.Enabled = Value;
            this.txtUser.Enabled = Value;
            this.txtPassword.Enabled = Value;

            btnGenerate.Enabled = Value;
            pictureBox1.Visible = !Value;
            chbGenerateAll.Enabled = Value;

        }

        #endregion

        #region Events View
        
        private void btnGenerate_Click(object sender, EventArgs e)
        {
            pCnn = "Server=" + txtServidor.Text + ";initial catalog=" + txtBD.Text + ";Integrated Security=false;User ID=" + txtUser.Text  + ";pwd=" + txtPassword.Text  + ";";
            if (ValidateData())
            {
                if (chbGenerateAll.Checked)                
                {                    
                
                    ExecuteGenerateAllCommands();
                    EnableControlsProcess(false);
                }
                Settings.Default.DB = txtBD.Text;
                Settings.Default.Server = txtServidor.Text;
                Settings.Default.User = txtUser.Text ;
                Settings.Default.Password  = txtPassword.Text ;
                Settings.Default.Save();

            }
        }

        private void CommandsGeneratorView_Load(object sender, EventArgs e)
        {
            ///desabilitamos la excepcion que salta cuando se quiere acceder a un control que fue ejecutado por otro subproceso
            CheckForIllegalCrossThreadCalls = false;


            ///inicializamos los datos de servidor y BD con los valores que se encuentran en la configiracion del programa
            txtBD.Text = Settings.Default.DB;
            txtServidor.Text = Settings.Default.Server;
            txtUser.Text = Settings.Default.User;
            txtPassword.Text = Settings.Default.Password;
            ///Cargamos los 
            LoadFilesCommands();
            

        }

        private void chbGenerateAll_CheckedChanged(object sender, EventArgs e)
        {
           
        }

        #endregion 

        #region Procces Asyncronos       

        /// <summary>
        /// Metodo que ejecuta la generacion de los comandos de todos los modulos procesandolo de una manera asincrona
        /// </summary>
        [STAThread]
        public void ExecuteGenerateAllCommands()
        {
            CommandsGeneratorView obj = this;
            GenertateAllCommandsDelegate Delegate1 = new GenertateAllCommandsDelegate(GenerateCommandsAllModules);
            Delegate1.BeginInvoke(new AsyncCallback(GenerateAllCommandsCallback), Delegate1);

        }

        /// <summary>
        /// Metodo que se dispara cuando termina de procesar la llamada asincrona
        /// </summary>
        /// <param name="ar"></param>
        private void GenerateAllCommandsCallback(IAsyncResult ar)
        {
            GenertateAllCommandsDelegate asyncDelegate = (GenertateAllCommandsDelegate)ar.AsyncState;
            pScriptExecute = asyncDelegate.EndInvoke(ar).ToString();
           
        }

        /// <summary>
        /// Metodo que ejecuta la generacion de comandos especificos de manera asincrona
        /// </summary>
        [STAThread]
        public void ExecuteGenerateSpecificsCommands()
        {
            CommandsGeneratorView obj = this;
            GenertateSpecificsCommandsDelegate Delegate2 = new GenertateSpecificsCommandsDelegate(GenerateCommands);
            Delegate2.BeginInvoke(new AsyncCallback(GenerateSpecificsCommandsCallback), Delegate2);
            
        }

        /// <summary>
        /// Metodo que se dispara cuando termina de procesar la llamada asincrona
        /// </summary>
        /// <param name="ar"></param>
        private void GenerateSpecificsCommandsCallback(IAsyncResult ar)
        {
            GenertateSpecificsCommandsDelegate asyncDelegate2 = (GenertateSpecificsCommandsDelegate)ar.AsyncState;
            pScriptExecute = asyncDelegate2.EndInvoke(ar).ToString();           

        }

        #endregion
      
    }
}

